﻿using Microsoft.AspNetCore.SignalR;
using OA.Infrastructure.SignalR.Abstractions;
using OA.Infrastructure.SignalR.Hubs;
using System.Security.Claims;

namespace OA.Infrastructure.Impl;

internal class SignalRService : ISignalRService
{
    private readonly IUserService _userService;
    private readonly IClientProxyFactory<NotifyHub> _realFactory;

    public IClientProxyFactory Factory { get; private set; } = null!;

    public SignalRService(IUserService userService, IClientProxyFactory factory)
    {
        _userService = userService;
        Factory = factory;

        _realFactory = factory.CreateGenericFactory<NotifyHub>();
    }

    public async Task SendAsync(string message, CancellationToken cancellationToken)
    {
        var userInfo = await GetCurrentUserInfoAsync(cancellationToken);

        if (userInfo is null)
        {
            return;
        }

        await _realFactory.CreateAllProxy().SendAsync("ReceiveNotification", new MessageRecord<string>()
        {
            Sender = userInfo.Name,
            Data = message,
            Level = MessageLevel.Information
        }, cancellationToken);
    }

    public async Task SendToUserAsync(string message, string account, CancellationToken cancellationToken)
    {
        var userInfo = await GetCurrentUserInfoAsync(cancellationToken);

        if (userInfo is null)
        {
            return;
        }

        await _realFactory
            .CreateUserProxy(account)
            .SendAsync(
                "ReceiveNotification",
                new MessageRecord<string>()
                {
                    Sender = userInfo.Name,
                    Data = message,
                    Level = MessageLevel.Information
                }, cancellationToken);
    }

    public async Task SendToGroupAsync(string message, string groupName, CancellationToken cancellationToken)
    {
        var userInfo = await GetCurrentUserInfoAsync(cancellationToken);

        if (userInfo is null)
        {
            return;
        }

        await _realFactory
            .CreateGroupProxy(groupName)
            .SendAsync(
                "ReceiveNotification",
                new MessageRecord<string>()
                {
                    Sender = userInfo.Name,
                    Data = message,
                    Level = MessageLevel.Information
                }, cancellationToken);
    }

    public async Task SendAsync(object data, string method, MessageLevel messageLevel = MessageLevel.Information, CancellationToken cancellationToken = default)
    {
        var userInfo = await GetCurrentUserInfoAsync(cancellationToken);

        if (userInfo is null)
        {
            return;
        }

        await _realFactory
            .CreateAllProxy()
            .SendAsync(
                method,
                new MessageRecord<object>()
                {
                    Sender = userInfo.Name,
                    Data = data,
                    Level = messageLevel
                }, cancellationToken);
    }

    private async Task<User.QueryModel?> GetCurrentUserInfoAsync(CancellationToken cancellationToken)
    {
        var username = App.HttpContext!.User.FindFirstValue(ClaimTypes.Name);
        var result = await _userService.GetUserInfoAsync(username, cancellationToken);

        return result.Status == OperationalResult.SUCCESS ? result.Data : null;
    }
}